package com.github.WhiteMagic2014.gptApi.Assistant.Thread.Message;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.WhiteMagic2014.gptApi.Assistant.pojo.ThreadMessage;
import com.github.WhiteMagic2014.gptApi.Assistant.pojo.ThreadMessageAttachment;
import com.github.WhiteMagic2014.gptApi.GptRequest;
import com.github.WhiteMagic2014.tool.GptTool;
import com.github.WhiteMagic2014.util.GptHttpUtil;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @Description: Create a message.
 * @author: magic chen
 * @date: 2023/11/16 18:20
 * https://platform.openai.com/docs/api-reference/messages/createMessage
 **/
public class CreateMessageRequest extends GptRequest {

    public CreateMessageRequest server(String server) {
        this.server = server;
        return this;
    }

     private final String url = "/v1/threads/{thread_id}/messages";

    public CreateMessageRequest gptHttpUtil(GptHttpUtil gptHttpUtil) {
        this.gptHttpUtil = gptHttpUtil;
        return this;
    }

    public CreateMessageRequest key(String key) {
        this.key = key;
        return this;
    }

    public CreateMessageRequest organization(String organization) {
        this.org = organization;
        return this;
    }
    // params

    /**
     * Required
     * The ID of the thread to create a message for.
     */
    private String thread_id;

    public CreateMessageRequest threadId(String threadId) {
        this.thread_id = threadId;
        return this;
    }

    /**
     * Required
     * The role of the entity that is creating the message.
     */
    private String role = "user";

    /**
     * Indicates the message is sent by an actual user and should be used in most cases to represent user-generated messages.
     */
    public CreateMessageRequest roleUser() {
        this.role = "user";
        return this;
    }

    /**
     * Indicates the message is generated by the assistant. Use this value to insert messages from the assistant into the conversation.
     */
    public CreateMessageRequest roleAssistant() {
        this.role = "assistant";
        return this;
    }

    /**
     * Required (chose one of  content or contents)
     * The text contents of the message.
     */
    private String content;

    public CreateMessageRequest content(String content) {
        this.content = content;
        return this;
    }

    /**
     * Required  (chose one of  content or contents)
     * <p>
     * Array of content parts
     * An array of content parts with a defined type, each can be of type text or images can be passed with image_url or image_file.
     * Image types are only supported on Vision-compatible models.
     */
    private List<JSONObject> contents = new ArrayList<>();

    public CreateMessageRequest addTextContent(String content) {
        JSONObject con = new JSONObject();
        con.put("text", content);
        con.put("type", "text");
        contents.add(con);
        return this;
    }

    /**
     * @param url    The external URL of the image, must be a supported image types: jpeg, jpg, png, gif, webp.
     * @param detail Specifies the detail level of the image. low uses fewer tokens, you can opt in to high resolution using high. Default value is auto
     * @return
     */
    public CreateMessageRequest addImageURLContent(String url, String detail) {
        JSONObject con = new JSONObject();
        con.put("type", "image_url");
        JSONObject img = new JSONObject();
        img.put("url", url);
        img.put("detail", detail);
        con.put("image_url", img);
        contents.add(con);
        return this;
    }

    public CreateMessageRequest addImageURLContent(String url) {
        return addImageURLContent(url, "auto");
    }


    /**
     * @param fileId The File ID of the image in the message content. Set purpose="vision" when uploading the File if you need to later display the file content.
     * @param detail Specifies the detail level of the image if specified by the user. low uses fewer tokens, you can opt in to high resolution using high.
     * @return
     */
    public CreateMessageRequest addImageFileContent(String fileId, String detail) {
        JSONObject con = new JSONObject();
        con.put("type", "image_file");
        JSONObject img = new JSONObject();
        img.put("file_id", fileId);
        img.put("detail", detail);
        con.put("image_file", img);
        contents.add(con);
        return this;
    }

    public CreateMessageRequest addImageFileContent(String fileId) {
        return addImageFileContent(fileId, "auto");
    }


    /**
     * Optional
     * A list of files attached to the message, and the tools they should be added to.
     */
    private List<ThreadMessageAttachment> attachments = new ArrayList<>();

    public CreateMessageRequest attachments(List<ThreadMessageAttachment> attachments) {
        this.attachments = attachments;
        return this;
    }

    /**
     * @param fileId The ID of the file to attach to the message.
     * @param tool   The tools to add this file to the message
     * @return
     */
    public CreateMessageRequest addAttachments(String fileId, GptTool tool) {
        ThreadMessageAttachment attachment = new ThreadMessageAttachment();
        attachment.setFile_id(fileId);
        attachment.setTools(Collections.singletonList(tool));
        attachments.add(attachment);
        return this;
    }

    /**
     * @param fileId The ID of the file to attach to the message.
     * @param tools  The tools to add this file to the message
     * @return
     */
    public CreateMessageRequest addAttachments(String fileId, List<GptTool> tools) {
        ThreadMessageAttachment attachment = new ThreadMessageAttachment();
        attachment.setFile_id(fileId);
        attachment.setTools(tools);
        attachments.add(attachment);
        return this;
    }


    /**
     * Set of 16 key-value pairs that can be attached to an object.
     * This can be useful for storing additional information about the object in a structured format.
     * Keys can be a maximum of 64 characters long and values can be a maxium of 512 characters long.
     */
    private JSONObject metadata = new JSONObject();

    public CreateMessageRequest metadata(JSONObject metadata) {
        this.metadata = metadata;
        return this;
    }

    public CreateMessageRequest addMetadata(String key, String value) {
        metadata.put(key, value);
        return this;
    }


    @Override
    protected String sendHook() {
        if (thread_id == null || thread_id.isEmpty()) {
            throw new RuntimeException("missing threadId");
        }
        JSONObject param = new JSONObject();
        if (role == null || role.isEmpty()) {
            throw new RuntimeException("missing role");
        }
        param.put("role", role);

        if (content != null && !contents.isEmpty()) {
            throw new RuntimeException("chose one of content or contents");
        } else {
            if (!contents.isEmpty()) {
                param.put("content", contents);
            } else {
                param.put("content", content);
            }
        }
        if (!attachments.isEmpty()) {
            param.put("attachments", attachments);
        }
        if (metadata != null && !metadata.isEmpty()) {
            param.put("metadata", metadata);
        }
        return gptHttpUtil.post(server + url.replace("{thread_id}", thread_id), key, org, param);
    }

    public ThreadMessage sendForThreadMessage() {
        return JSON.toJavaObject(send(), ThreadMessage.class);
    }

}
